// FtmConfig.cpp : Defines the entry point for the console application.
//

#include "resource.h"
#include <aygshell.h>
#include <windows.h>
#include <commctrl.h>
#include <storemgr.h>
#include "nand.h"
#include "calibrate.h"

//----------- Type definition -----------
typedef struct  
{
    DWORD dwCtrlId;
    long* plValueAddr;
    BOOL  bSetFtm;
} WORK_STATE_MAP;


//-------------- Constants --------------

//Modem flag value (for MODEM_FLAG_INFO)
enum
{
    MODEM_FLAG_SET      = 0xffff0000,
    MODEM_FLAG_NOT_SET  = -1
};

//Work state value (for PRODUCTION_PARAM_STRU)
enum
{
    WORK_STATE_TO_DO    = 0xffff0000,
    WORK_STATE_DONE     = 0,
    WORK_STATE_UNKNOWN  = (DWORD)(-1)
};

//Index value of combo box for each work state
enum
{
    ST_IDX_TO_DO,
    ST_IDX_DONE
};

const DWORD WORK_STATE_COUNT = 2;

const TCHAR* WORK_STATE_STR[WORK_STATE_COUNT] = {
    _T("To do"),
    _T("Done")
};

const DWORD WORK_COUNT = 6;


//----------- Static variables -----------
static HWND                     f_hMainWnd;
static HANDLE                   f_hStore = INVALID_HANDLE_VALUE;
static MODEM_FLAG_INFO          f_modemFlagInfo;
static PRODUCTION_PARAM_STRU    f_productionInfo;

static WORK_STATE_MAP f_workStateMap[WORK_COUNT] = {
    {IDC_CMB_CALI, &f_productionInfo.lCTFlag, TRUE},
    {IDC_CMB_FT, &f_productionInfo.lFTFlag, TRUE},
    {IDC_CMB_BMMI, &f_productionInfo.lBMMIFlag, FALSE},
    {IDC_CMB_AMMI, &f_productionInfo.lAMMIFlag, FALSE},
    {IDC_CMB_ANT, &f_productionInfo.lMTFlag, TRUE},
    {IDC_CMB_IMEI, &f_productionInfo.lIMEIFlag, TRUE}
};


//----------- Static variables -----------
void InitComboBoxes(HWND hWnd)
{
    int i,j;

    for (i=0; i<WORK_COUNT; i++)
    {
        for (j=0; j<WORK_STATE_COUNT; j++)
        {
            ::SendDlgItemMessage(hWnd, f_workStateMap[i].dwCtrlId, 
                CB_ADDSTRING, 0, (LPARAM)WORK_STATE_STR[j]);
        }
    }
}


BOOL InitNvOperation()
{
    const TCHAR* szProfile = L"MSFlash";
    STOREINFO  storeInfo;

    memset(&storeInfo, 0, sizeof(storeInfo));
    storeInfo.cbSize = sizeof(storeInfo);
    storeInfo.dwDeviceType = STORAGE_DEVICE_TYPE_FLASH;

    HANDLE hFind = FindFirstStore(&storeInfo);
    if(INVALID_HANDLE_VALUE == hFind)
    {
        return FALSE;
    }

    BOOL bFound = TRUE;
    while(_tcsicmp(storeInfo.sdi.szProfile, szProfile) != 0)
    {
        if (!FindNextStore(hFind, &storeInfo))
        {
            bFound = FALSE;
            break;
        }
    }

    FindCloseStore(hFind);

    if (!bFound)
    {
        return FALSE;
    }

    f_hStore = OpenStore(storeInfo.szDeviceName);
    if (INVALID_HANDLE_VALUE == f_hStore)
    {
        return FALSE;
    }

    return TRUE;
}


void DeinitNvOperation()
{
    if (f_hStore != INVALID_HANDLE_VALUE)
    {
        CloseHandle(f_hStore);
    }
}


BOOL ReadProductionFlag(PRODUCTION_PARAM_STRU* pstProdParm)
{
    if (INVALID_HANDLE_VALUE == f_hStore)
    {
        return FALSE;
    }

    DWORD addr = NV_PRODUCTIONPARAM_ADDR;
    if (!DeviceIoControl(f_hStore, IOCTL_FMD_READ_NV, &addr, sizeof(addr), 
        pstProdParm, sizeof(PRODUCTION_PARAM_STRU), NULL, NULL))
    {
        return FALSE;
    }

    return TRUE;
}


BOOL WriteProductionFlag(PRODUCTION_PARAM_STRU* pstProdParm)
{
    if (INVALID_HANDLE_VALUE == f_hStore)
    {
        return FALSE;
    }

    DWORD addr = NV_PRODUCTIONPARAM_ADDR;
    if (!DeviceIoControl(f_hStore, IOCTL_FMD_WRITE_NV, pstProdParm, sizeof(PRODUCTION_PARAM_STRU), 
        &addr, sizeof(addr), NULL, NULL))
    {
        return FALSE;
    }

    return TRUE;
}


BOOL ReadModemFlag(MODEM_FLAG_INFO* pstModemFlag)
{
    if (INVALID_HANDLE_VALUE == f_hStore)
    {
        return FALSE;
    }

    DWORD addr = NV_MODEMFLAG_ADDR;
    if (!DeviceIoControl(f_hStore, IOCTL_FMD_READ_NV, &addr, sizeof(addr), 
        pstModemFlag, sizeof(MODEM_FLAG_INFO), NULL, NULL))
    {
        return FALSE;
    }

    return TRUE;
}


BOOL WriteModemFlag(MODEM_FLAG_INFO* pstModemFlag)
{
    if (INVALID_HANDLE_VALUE == f_hStore)
    {
        return FALSE;
    }

    DWORD addr = NV_MODEMFLAG_ADDR;
    if (!DeviceIoControl(f_hStore, IOCTL_FMD_WRITE_NV, pstModemFlag, sizeof(MODEM_FLAG_INFO), 
        &addr, sizeof(addr), NULL, NULL))
    {
        return FALSE;
    }

    return TRUE;
}


void GetWorkState(UINT comboId, long* pState)
{
    DWORD index;

    index = ::SendDlgItemMessage(f_hMainWnd, comboId, CB_GETCURSEL, 0, 0);
    if (ST_IDX_TO_DO == index)
    {
        *pState = WORK_STATE_TO_DO;
    }
    else if (ST_IDX_DONE == index)
    {
        *pState = WORK_STATE_DONE;
    }
    else
    {
        *pState = WORK_STATE_UNKNOWN;
    }
}


void SetWorkState(UINT comboId, long state)
{
    DWORD index;

    if (WORK_STATE_DONE == state)
    {
        index = ST_IDX_DONE;
    }
    else
    {
        index = ST_IDX_TO_DO;
    }

    ::SendDlgItemMessage(f_hMainWnd, comboId, CB_SETCURSEL, index, 0);
}


BOOL ShowCurrConfig()
{
    if (!ReadModemFlag(&f_modemFlagInfo))
    {
        return FALSE;
    }
    
    if (!ReadProductionFlag(&f_productionInfo))
    {
        return FALSE;
    }

    for (int i=0; i<WORK_COUNT; i++)
    {
        SetWorkState(f_workStateMap[i].dwCtrlId, *f_workStateMap[i].plValueAddr);
    }

    return TRUE;
}


BOOL WriteNewConfig()
{
    BOOL  bProdFlagChanged = FALSE;
    BOOL  ret = TRUE;
    long temp;

    f_modemFlagInfo.m_modemfg = MODEM_FLAG_NOT_SET;

    for (int i=0; i<WORK_COUNT; i++)
    {
        GetWorkState(f_workStateMap[i].dwCtrlId, &temp);
        if (*f_workStateMap[i].plValueAddr != temp)
        {
            *f_workStateMap[i].plValueAddr = temp;
            bProdFlagChanged = TRUE;
        }

        if (*f_workStateMap[i].plValueAddr == WORK_STATE_TO_DO &&
            f_workStateMap[i].bSetFtm)
        {
            f_modemFlagInfo.m_modemfg = MODEM_FLAG_SET;
        }
    }

    ret &= WriteModemFlag(&f_modemFlagInfo);

    if (bProdFlagChanged)
    {
        ret &= WriteProductionFlag(&f_productionInfo);
    }

    return ret;
}


BOOL CALLBACK ConfigDialogProc(
                         HWND hwndDlg, 
                         UINT uMsg, 
                         WPARAM wParam, 
                         LPARAM lParam)
{
    BOOL ret = TRUE;

    switch (uMsg)
    {
    case WM_INITDIALOG:
        f_hMainWnd = hwndDlg;

        SHINITDLGINFO sid;

        (void)ZeroMemory( &sid, sizeof( sid ) );
        sid.dwMask  = SHIDIM_FLAGS;
        sid.dwFlags = SHIDIF_SIZEDLGFULLSCREEN | SHIDIF_EMPTYMENU | SHIDIF_CANCELBUTTON;
        sid.hDlg    = hwndDlg;

        ::SHInitDialog( &sid);

        //Create menu bar
        SHMENUBARINFO mbi;

        memset(&mbi, 0, sizeof(SHMENUBARINFO));
        mbi.cbSize = sizeof(SHMENUBARINFO);
        mbi.hwndParent = hwndDlg;
        mbi.hInstRes = (HINSTANCE)GetModuleHandle(NULL);
        mbi.nToolBarId = IDR_MENUBAR;
        SHCreateMenuBar(&mbi);

        InitComboBoxes(hwndDlg);

        if (!InitNvOperation())
        {
            ::MessageBox(f_hMainWnd, _T("Failed to initialize NV operation."), _T("Error"), MB_OK);
            ::EndDialog(hwndDlg, IDCANCEL);
        }

        ShowCurrConfig();

        break;

    case WM_COMMAND:
        if(LOWORD(wParam) == IDCANCEL)
        {
            ::EndDialog(hwndDlg, IDCANCEL);
        }
        else if(LOWORD(wParam) == IDOK)
        {
            //Do nothing
        }
        else if(LOWORD(wParam) == IDM_SET)
        {
            if (WriteNewConfig())
            {
                ::MessageBox(f_hMainWnd, _T("Write config successfully."), _T("OK"), MB_OK);
            }
            else
            {
                ::MessageBox(f_hMainWnd, _T("Failed to write config."), _T("Error"), MB_OK);
            }
        }
        else if(LOWORD(wParam) == IDM_RESET)
        {
            ShowCurrConfig();
        }
        else
        {
            ret = FALSE;
        }
        break;

    case WM_DESTROY:
        DeinitNvOperation();
        break;

    default:
        ret = FALSE;
        break;
    }

    return ret;
}


int WINAPI WinMain(
    HINSTANCE hInstance, 
    HINSTANCE hPrevInstance, 
    LPWSTR lpCmdLine, 
    int nShowCmd 
)
{
	if(GetUserDefaultLangID() == 0x0804)
	{		
	    DialogBox((HINSTANCE)GetModuleHandle(NULL), 
	              MAKEINTRESOURCE(IDD_CONFIG_SCN),
	              NULL,
	              ConfigDialogProc);
	}
	else
	{
	    DialogBox((HINSTANCE)GetModuleHandle(NULL), 
	              MAKEINTRESOURCE(IDD_CONFIG_EN),
	              NULL,
	              ConfigDialogProc);		
	}	

	return 0;
}

